﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Neuron.Cell;
using System.Xml;


namespace Neuron.Cell.Control
{
    [Serializable()]
    public partial class ctrlPerceptron : UserControl
    {
        private Perceptron _perceptron = null;
        private bool _stimulationOn = false;

        private bool _clickAllowed = true;

        private int mouseX = 0;
        private int mouseY = 0;

        public delegate void delegateFireAction(ctrlPerceptron ctrl);

        public delegate void delegateDeleteMe(ctrlPerceptron ctrl);
        public event delegateDeleteMe DeleteMe;

        public delegate void delegateStopMovement();
        public event delegateStopMovement MovementStopped;


        public ctrlPerceptron()
        {
            InitializeComponent();

            toolTipPerceptron.SetToolTip(pictureBoxKonaktIN, "Draw an opened connection to this contatc plate \n to connect another perceptorn to this one.");
            toolTipPerceptron.SetToolTip(pictureBoxKontaktOUT, "Just klick left mouse button to start a connection. \n Then move the mouse in unpressed button state \n to an input contact plate on top of another perceptron.");
        }

        public Perceptron Perceptron
        {
            set
            {
                if (value != null)
                {
                    this._perceptron = value;
                    if (this._perceptron.ActivationFunction == ActivationFunctionEnum.receptor)
                    {
                        pictureBoxKonaktIN.Visible = false;
                        textBoxInput.Visible = false;
                    }
                    if (this._perceptron.ActivationFunction == ActivationFunctionEnum.actor)
                    {
                        pictureBoxKontaktOUT.Visible = false;
                        textBoxOutput.Visible = false;
                    }

                    this._perceptron.FireAction += UpdateValues;
                    this._perceptron.Control = this;
                    this.UpdateValues();

                    // Standardlabel is replaced by vertical namelabel
                    //this.labelName.Text = this._perceptron.Name;
                    StringFormat format = new StringFormat();
                    format.Alignment = StringAlignment.Near;
                    format.LineAlignment = StringAlignment.Near;
                    format.Trimming = StringTrimming.EllipsisCharacter;

                    Bitmap bmpName = new Bitmap(pictureBoxName.Height, pictureBoxName.Width);
                    Graphics g = Graphics.FromImage(bmpName);

                    //g.Clear();

                    SolidBrush brushText = new SolidBrush(this.ForeColor);
                    g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
                    g.DrawString(this._perceptron.Name, this.Font, brushText, new Rectangle(0, 0, bmpName.Width, bmpName.Height), format);
                    brushText.Dispose();

                    bmpName.RotateFlip(RotateFlipType.Rotate270FlipNone);
                    pictureBoxName.Image = bmpName;

                }
            }
            get
            {
                return this._perceptron;
            }
        }

        public void DrawClientConnectionsAutomatically()
        {
            if (this.Top < 0)
            {
                this.Top = 10;
            }
            if (this.Left < 0)
            {
                this.Left = 10;
            }

            // Draw connections to clients
            if (this._perceptron != null)
            {
                int i = 0;
                Perceptron senderPerceptron = this._perceptron.InputVectorGetPerceptronAtIndex(i);
                while (senderPerceptron != null)
                {
                    if ((senderPerceptron.Control != null)&&(senderPerceptron.Control.Parent != null))
                    {
                        if ((senderPerceptron.ActivationFunction != ActivationFunctionEnum.actor) &&
                            (senderPerceptron.ActivationFunction != ActivationFunctionEnum.receptor) &&
                            (senderPerceptron.ActivationFunction != ActivationFunctionEnum.trigger) &&
                            (senderPerceptron.ActivationFunction != ActivationFunctionEnum.buffer) &&
                            (this._perceptron.ActivationFunction != ActivationFunctionEnum.actor) &&
                            (this._perceptron.ActivationFunction != ActivationFunctionEnum.trigger) &&
                            (this._perceptron.ActivationFunction != ActivationFunctionEnum.buffer) &&
                            (this._perceptron.ActivationFunction != ActivationFunctionEnum.receptor))
                        {
                            System.Drawing.Pen myPen;
                            myPen = new System.Drawing.Pen(System.Drawing.Color.Blue);
                            myPen.Width = 2;
                            System.Drawing.Graphics formGraphics = senderPerceptron.Control.Parent.CreateGraphics();

                            int startX = senderPerceptron.Control.Left + (senderPerceptron.Control.Width / 2);
                            int startY = senderPerceptron.Control.Top + pictureBoxBackground.Height;

                            int destX = this.Left + (pictureBoxBackground.Width / 2);
                            int destY = this.Top;

                            if (startY < destY)
                            {
                                //formGraphics.DrawLine(myPen, startX, startY, destX, destY);
                                formGraphics.DrawLine(myPen, startX, startY, startX, startY + 5 + i);
                                formGraphics.DrawLine(myPen, startX, startY + 5 + i, destX, startY + 5 + i);
                                formGraphics.DrawLine(myPen, destX, startY + 5 + i, destX, destY);
                            }

                            if ((startY > destY) && (startX > destX))
                            {
                                formGraphics.DrawLine(myPen, startX, startY, startX, startY + 5);
                                formGraphics.DrawLine(myPen, startX, startY + 5, startX - (this.Width / 2) - 5, startY + 5);
                                formGraphics.DrawLine(myPen, startX - (this.Width / 2) - 5, startY + 5, startX - (this.Width / 2) - 5, destY - 5);
                                formGraphics.DrawLine(myPen, startX - (this.Width / 2) - 5, destY - 5, destX, destY - 5);
                                formGraphics.DrawLine(myPen, destX, destY - 5, destX, destY);
                            }
                            if ((startY > destY) && (startX < destX))
                            {
                                formGraphics.DrawLine(myPen, startX, startY, startX, startY + 5);
                                formGraphics.DrawLine(myPen, startX, startY + 5, startX + (this.Width / 2) + 5, startY + 5);
                                formGraphics.DrawLine(myPen, startX + (this.Width / 2) + 5, startY + 5, startX + (this.Width / 2) + 5, destY - 5);
                                formGraphics.DrawLine(myPen, startX + (this.Width / 2) + 5, destY - 5, destX, destY - 5);
                                formGraphics.DrawLine(myPen, destX, destY - 5, destX, destY);
                            }


                            myPen.Dispose();
                            formGraphics.Dispose();
                        }

                        if (((senderPerceptron.ActivationFunction == ActivationFunctionEnum.receptor) ||
                            (senderPerceptron.ActivationFunction == ActivationFunctionEnum.trigger) ||
                            (senderPerceptron.ActivationFunction == ActivationFunctionEnum.buffer)) &&
                            (this._perceptron.ActivationFunction != ActivationFunctionEnum.actor))
                        {
                            System.Drawing.Pen myPen;
                            myPen = new System.Drawing.Pen(System.Drawing.Color.DarkRed);
                            myPen.Width = 2;
                            System.Drawing.Graphics formGraphics = senderPerceptron.Control.Parent.CreateGraphics();

                            int startX = senderPerceptron.Control.Left + (senderPerceptron.Control.Width / 2);
                            int startY = senderPerceptron.Control.Top + pictureBoxBackground.Height;

                            int destX = this.Left + (pictureBoxBackground.Width / 2);
                            int destY = this.Top;

                            formGraphics.DrawLine(myPen, startX, startY, destX, destY);

                            myPen.Dispose();
                            formGraphics.Dispose();
                        }

                        if ((senderPerceptron.ActivationFunction != ActivationFunctionEnum.receptor) &&
                            (this._perceptron.ActivationFunction == ActivationFunctionEnum.actor))
                        {
                            System.Drawing.Pen myPen;
                            myPen = new System.Drawing.Pen(System.Drawing.Color.DarkGreen);
                            myPen.Width = 2;
                            System.Drawing.Graphics formGraphics = senderPerceptron.Control.Parent.CreateGraphics();

                            int startX = senderPerceptron.Control.Left + (senderPerceptron.Control.Width / 2);
                            int startY = senderPerceptron.Control.Top + pictureBoxBackground.Height;

                            int destX = this.Left + (pictureBoxBackground.Width / 2);
                            int destY = this.Top;

                            formGraphics.DrawLine(myPen, startX, startY, destX, destY);

                            myPen.Dispose();
                            formGraphics.Dispose();
                        }

                    }
                    i += 1;
                    senderPerceptron = this._perceptron.InputVectorGetPerceptronAtIndex(i);
                }
            }
        }

        private void UpdateValues()
        {
            if (this.InvokeRequired)
                this.Invoke(new MethodInvoker(UpdateValues));
            else
            {
                this.textBoxHardLimit.Text = Convert.ToString(_perceptron.HardLimit);
                this.textBoxInput.Text = Convert.ToString(_perceptron.VectorIN);

                this.textBoxOutput.Text = Convert.ToString(_perceptron.VectorOUT);
                if (_perceptron.VectorOUT != 0)
                {
                    if (_perceptron.ActivationFunction == ActivationFunctionEnum.receptor)
                    {
                        pictureBoxBackground.Image = imageList1.Images[8];
                        this._stimulationOn = true;
                    }
                    textBoxOutput.BackColor = Color.Green;
                    textBoxOutput.ForeColor = Color.White;
                }
                else
                {
                    if (_perceptron.ActivationFunction == ActivationFunctionEnum.receptor)
                    {
                        pictureBoxBackground.Image = imageList1.Images[7];
                        this._stimulationOn = false;
                    }
                    textBoxOutput.BackColor = Color.White;
                    textBoxOutput.ForeColor = Color.Black;
                }

                switch (_perceptron.ActivationFunction)
                {
                    case ActivationFunctionEnum.hlim:
                        {
                            if (!_perceptron.OnNeuronConnected)
                            {
                                pictureBoxBackground.Image = imageList1.Images[0];
                            }
                            else
                            {
                                pictureBoxBackground.Image = imageList1.Images[1];
                            }
                            break;
                        }
                    case ActivationFunctionEnum.pwl:
                        {
                            if (!_perceptron.OnNeuronConnected)
                            {
                                pictureBoxBackground.Image = imageList1.Images[2];
                            }
                            else
                            {
                                pictureBoxBackground.Image = imageList1.Images[3];
                            }
                            break;
                        }
                    case ActivationFunctionEnum.sig:
                        {
                            if (!_perceptron.OnNeuronConnected)
                            {
                                pictureBoxBackground.Image = imageList1.Images[4];
                            }
                            else
                            {
                                pictureBoxBackground.Image = imageList1.Images[5];
                            }
                            break;
                        }
                    case ActivationFunctionEnum.receptor:
                        {
                            pictureBoxBackground.Image = imageList1.Images[7];
                            break;
                        }
                    case ActivationFunctionEnum.trigger:
                        {
                            pictureBoxBackground.Image = imageList1.Images[13];
                            break;
                        }
                    case ActivationFunctionEnum.buffer:
                        {
                            pictureBoxBackground.Image = imageList1.Images[12];
                            break;
                        }
                    case ActivationFunctionEnum.actor:
                        {
                            /*
                            if (_perceptron.VectorIN == _perceptron.HardLimit)
                            {
                                pictureBoxBackground.Image = imageList1.Images[11];
                            }
                            */
                            if (_perceptron.VectorIN < _perceptron.HardLimit)
                            {
                                pictureBoxBackground.Image = imageList1.Images[10];
                            }
                            if (_perceptron.VectorIN >= _perceptron.HardLimit)
                            {
                                pictureBoxBackground.Image = imageList1.Images[9];
                            }
                            break;
                        }
                    default:
                        pictureBoxBackground.Image = imageList1.Images[6];
                        break;
                }
            }
        }

        private void pictureBoxBackground_Click(object sender, EventArgs e)
        {
            if (this._clickAllowed == false) return;

            if (_perceptron == null) return;

            if (_perceptron.ActivationFunction == ActivationFunctionEnum.receptor)
            {
                _stimulationOn = !_stimulationOn;
                if (_stimulationOn)
                {
                    _perceptron.stimulate(1);
                    pictureBoxBackground.Image = imageList1.Images[8];
                }
                else
                {
                    _perceptron.stimulate(0);
                    pictureBoxBackground.Image = imageList1.Images[7];
                }

                return;
            }

            if (_perceptron.ActivationFunction == ActivationFunctionEnum.hlim)
            {
                if (_perceptron.OnNeuronConnected)
                {
                    _perceptron.RemoveOnNeuron();
                    _perceptron.ActivationFunction = ActivationFunctionEnum.pwl;
                    pictureBoxBackground.Image = imageList1.Images[2];
                    return;
                }
                else
                {
                    _perceptron.AddOnNeuron();
                    pictureBoxBackground.Image = imageList1.Images[1];
                }

            }

            if (_perceptron.ActivationFunction == ActivationFunctionEnum.pwl)
            {
                if (_perceptron.OnNeuronConnected)
                {
                    _perceptron.RemoveOnNeuron();
                    _perceptron.ActivationFunction = ActivationFunctionEnum.sig;
                    pictureBoxBackground.Image = imageList1.Images[4];
                    return;
                }
                else
                {
                    _perceptron.AddOnNeuron();
                    pictureBoxBackground.Image = imageList1.Images[3];
                }
            }

            if (_perceptron.ActivationFunction == ActivationFunctionEnum.sig)
            {
                if (_perceptron.OnNeuronConnected)
                {
                    _perceptron.RemoveOnNeuron();
                    _perceptron.ActivationFunction = ActivationFunctionEnum.buffer;
                    pictureBoxBackground.Image = imageList1.Images[12];
                    _perceptron.StartDelayBuffer();
                    return;
                }
                else
                {
                    _perceptron.AddOnNeuron();
                    pictureBoxBackground.Image = imageList1.Images[5];
                }
            }

            if (_perceptron.ActivationFunction == ActivationFunctionEnum.buffer)
            {
                _perceptron.Shutdown();
                _perceptron.ActivationFunction = ActivationFunctionEnum.trigger;
                pictureBoxBackground.Image = imageList1.Images[13];
                _perceptron.StartTrigger();
                return;
            }

            if (_perceptron.ActivationFunction == ActivationFunctionEnum.trigger)
            {
                _perceptron.Shutdown();
                _perceptron.ActivationFunction = ActivationFunctionEnum.hlim;
                pictureBoxBackground.Image = imageList1.Images[0];
                return;
            }


        }

        private void pictureBoxBackground_MouseDown(object sender, MouseEventArgs e)
        {
            mouseX = e.X;
            mouseY = e.Y;
        }

        private void ctrlPerceptron_MouseMove(object sender, MouseEventArgs e)
        {
        }

        private void pictureBoxBackground_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                this._clickAllowed = false;
                Point mousePoint = new Point(e.X, e.Y);
                if ((e.Y >= -10)&&(e.Y < 40))
                {

                    Point absMousePoint = this.PointToScreen(mousePoint);
                    Point absCtrlPoint = this.Parent.PointToScreen(new Point(this.Left, this.Top));

                    int deltaX = absCtrlPoint.X - absMousePoint.X;
                    int deltaY = absCtrlPoint.Y - absMousePoint.Y;

                    Point relPoint = this.Parent.PointToClient(absMousePoint);
                    this.Left = relPoint.X;
                    this.Top = relPoint.Y;
                }
            }
        }

        private void pictureBoxBackground_MouseUp(object sender, MouseEventArgs e)
        {
            this._clickAllowed = true;

            if (MovementStopped != null)
            {
                MovementStopped();
            }
        }

        public void getXMLElement(XmlDocument xmlDoc, XmlElement parentNetwork, bool inclWeighting)
        {
            XmlElement XmlElementControlPerceptron = xmlDoc.CreateElement("Control");

            XmlElementControlPerceptron.SetAttribute("Type", "Perceptron");
            XmlElementControlPerceptron.SetAttribute("Name", this.Perceptron.Name);
            XmlElementControlPerceptron.SetAttribute("Left", Convert.ToString(this.Left));
            XmlElementControlPerceptron.SetAttribute("Top", Convert.ToString(this.Top));

            this.Perceptron.getXMLElement(xmlDoc, XmlElementControlPerceptron, inclWeighting);

            parentNetwork.AppendChild(XmlElementControlPerceptron);

            return;
        }


        private void textBoxHardLimit_TextChanged(object sender, EventArgs e)
        {
            this._perceptron.HardLimit = double.Parse(textBoxHardLimit.Text.Replace(',', '.'), System.Globalization.CultureInfo.InvariantCulture);
            //Convert.ToDouble(textBoxHardLimit.Text);
        }

        public event delegateFireAction ClickStartConnection;
        public event delegateFireAction ClickEndConnection;

        private void pictureBoxKonaktIN_Click(object sender, EventArgs e)
        {
            if (!this._clickAllowed) return;

            if (this.ClickEndConnection != null)
            {
                this.ClickEndConnection(this);
            }
        }

        private void pictureBoxKontaktOUT_Click(object sender, EventArgs e)
        {
            if (!this._clickAllowed) return;

            if (this.ClickStartConnection != null)
            {
                this.ClickStartConnection(this);
            }
        }

        private void pictureBoxBackground_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                if (DeleteMe != null)
                {
                    this.DeleteMe(this);
                }

            }
        }
    }
}
